package com.key.w8.http1.handler.codec;

import com.alibaba.fastjson2.JSONObject;
import com.key.w8.http1.entity.HttpRequest;
import com.key.w8.http1.entity.HttpResponse;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;

import static com.key.w8.http1.constant.Constants.JSON_CONTENT_TYPE;

/**
 * @Author: k8
 * @CreateTime: 2025-03-11
 * @Version: 1.0
 */
public class DefaultCodecBuilder implements CodecBuilder {

    List<HttpObjectServerResolver> httpObjectServerResolvers = new LinkedList<>();
    List<HttpObjectClientResolver> httpObjectClientResolvers = new LinkedList<>();

    public DefaultCodecBuilder() {

    }

    @Override
    public void addHttpObjectServerResolver(HttpObjectServerResolver requestResolver) {
        assert requestResolver != null;
        httpObjectServerResolvers.add(requestResolver);
    }

    @Override
    public void addHttpObjectClientResolver(HttpObjectClientResolver httpObjectClientResolver) {
        assert httpObjectClientResolver != null;
        httpObjectClientResolvers.add(httpObjectClientResolver);
    }

    @Override
    public Http1Codec build() {
        ConnectionHttp1Codec codec = new ConnectionHttp1Codec();
        HttpObjectServerResolver resolver = new HttpObjectServerResolverComposit(this.httpObjectServerResolvers);
        HttpObjectClientResolver httpObjectClientResolverComposit = new HttpObjectClientResolverComposit(this.httpObjectClientResolvers);
        codec.setHttpObjectServerResolver(resolver);
        codec.setHttpObjectClientResolver(httpObjectClientResolverComposit);
        return codec;
    }

    /**
     * 简单的服务器json处理
     */



    static class HttpObjectServerResolverComposit implements HttpObjectServerResolver {
        List<HttpObjectServerResolver> httpObjectResolverIns;

        public HttpObjectServerResolverComposit(List<HttpObjectServerResolver> httpObjectResolverIns) {
            this.httpObjectResolverIns = httpObjectResolverIns;
        }

        @Override
        public boolean canResolverRequestIn(FullHttpRequest fullHttpRequest) {
            return true;
        }

        @Override
        public HttpRequest resolverRequestIn(FullHttpRequest fullHttpRequest) {
            HttpRequest request = null;
            for (HttpObjectServerResolver requestResolver : httpObjectResolverIns) {
                if (requestResolver.canResolverRequestIn(fullHttpRequest)) {
                    try {
                        request = requestResolver.resolverRequestIn(fullHttpRequest);
                        if (request != null) return request;
                    } catch (Throwable throwable) {
                        continue;
                    }
                }
            }
            return null;
        }
        @Override
        public boolean canResolverResponseOut(HttpResponse httpResponse) {
            return true;
        }

        @Override
        public FullHttpResponse resolverResponseOut(HttpResponse httpResponse, ByteBufAllocatorHolder allocatorHolder) {
            FullHttpResponse fullHttpResponse = null;
            for (HttpObjectServerResolver requestResolver : httpObjectResolverIns) {
                if (requestResolver.canResolverResponseOut(httpResponse)) {
                    try {
                        fullHttpResponse = requestResolver.resolverResponseOut(httpResponse,allocatorHolder);
                        if (fullHttpResponse != null) return fullHttpResponse;
                    } catch (Throwable throwable) {
                    }
                }
            }
            return null;
        }
    }

    static class HttpObjectClientResolverComposit implements HttpObjectClientResolver {
        private List<HttpObjectClientResolver> httpObjectClientResolvers;

        public HttpObjectClientResolverComposit(List<HttpObjectClientResolver> httpObjectClientResolvers) {
            this.httpObjectClientResolvers = httpObjectClientResolvers;
        }

        @Override
        public boolean canResolverRequestOut(HttpRequest httpRequest) {
            return true;
        }

        @Override
        public FullHttpRequest resolverRequestOut(HttpRequest httpRequest, ByteBufAllocatorHolder allocatorHolder) {
            FullHttpRequest fullHttpRequest = null;
            for (HttpObjectClientResolver requestResolver : httpObjectClientResolvers) {
                if (requestResolver.canResolverRequestOut(httpRequest)) {
                    try {
                        fullHttpRequest = requestResolver.resolverRequestOut(httpRequest, allocatorHolder);
                        if (fullHttpRequest != null) return fullHttpRequest;
                    } catch (Throwable throwable) {
                        continue;
                    }
                }
            }
            return null;
        }

        @Override
        public boolean canResolverResponseIn(FullHttpResponse fullHttpResponse) {
            return true;
        }

        @Override
        public HttpResponse resolverResponseIn(FullHttpResponse fullResponse) {
            HttpResponse response = null;
            for (HttpObjectClientResolver responseResolver : httpObjectClientResolvers) {
                if (responseResolver.canResolverResponseIn(fullResponse)) {
                    try {
                        response = responseResolver.resolverResponseIn(fullResponse);
                        if (response != null) return response;
                    } catch (Throwable throwable) {
                        continue;
                    }
                }
            }
            return null;
        }
    }

    public static Charset getCharSet(String contentType) {
        Charset charset = null;
        if (contentType.contains("charset=")) {
            String[] split = contentType.split("charset=");
            if (split.length > 1) {
                for (int i = 1; i < split.length; i++) {
                    String trim = split[i].trim();
                    if (Charset.isSupported(trim)) {
                        charset = Charset.forName(trim);
                        break;
                    }
                }
                if (charset == null) charset = StandardCharsets.UTF_8;
            } else {
                charset = StandardCharsets.UTF_8;
            }
        } else {
            charset = StandardCharsets.UTF_8;
        }
        return charset;
    }
}
